package com.binguo.wxapi.wxpay;

import com.alibaba.druid.support.json.JSONUtils;
import com.binguo.common.util.JsonUtil;
import com.binguo.common.util.LoggerUtil;
import com.binguo.model.mapper.WxPayOrderMapper;
import com.binguo.model.model.WxPayOrder;
import com.binguo.service.OrderService;
import com.github.wxpay.sdk.WXPay;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Condition;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.StringReader;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 服务号支付
 * 主商户AppID：wxe786085d47d6cbf4
 * 主商户号：1268823101
 * 主商户AppSecret：147107f302f54c94f40010347934d2b1
 * 商户API密钥：hangzhouyiling123456852365475232
 */
@Service
public class WXServerPayService {
    private static Logger logger = LoggerFactory.getLogger(WXServerPayService.class);


    @Autowired
    OrderService orderService;


    public static String appid = "wxe786085d47d6cbf4";
    public static String mch_id = "1268823101";
    public static String appKey = "hangzhouyiling123456852365475232";

    public static String sub_appid = "wx099356561cb9c60f";//
    public static String sub_mch_id = "1508590551";
    public static String appSecret = "147107f302f54c94f40010347934d2b1";
    public static String success = "SUCCESS";
    private static final String payUrl = "http://binguoai.com/appapi/wxpay/callback";
    public static String notifyUrl = "https://binguoai.com/serverpay/notice";
    public static String serverPayNotifyUrl = "https://binguoai.com/api/wxapp/serverpay/notity";

    private WXPay wxPay = new WXPay(new WXServerPayConfig());
    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    private static final String responseSuccess = "<xml>" +
            "<return_code><![CDATA[SUCCESS]]></return_code>" +
            "<return_msg><![CDATA[OK]]></return_msg>" +
            "</xml>";

    private static final String responseFail = "<xml>" +
            "<return_code><![CDATA[FAIL]]></return_code>" +
            "<return_msg><![CDATA[sign error]]></return_msg>" +
            "</xml>";


    /**
     *
     名称	变量名	必填	类型	示例值	描述
     公众帐号ID	appid	是	String(32)	wx931386123456789e	银行服务商的公众账号 ID
     商户号	mch_id	是	String(32)	1451234567	银行服务商的商户号
     特约商户号	sub_mch_id	是	String(32)	10000101	银行服务商报备的特约商户识别码
     关联APPID	sub_appid	是	String(32)	wx931386123456789e	绑定特约商户或渠道公众号、小程序、APP支付等对应的APPID
     签名	sign	是	String(32)	C380BEC2BFD727A4B6845133519F3AD6
     * @throws Exception
     */

    public void test(String subappid) throws Exception{
        if (StringUtils.hasText(subappid)) {
            subappid = sub_appid;
        }


        String url = "https://api.mch.weixin.qq.com/secapi/mch/addsubdevconfig";

        String stringB = "appid=" + appid
                + "&mch_id=" + mch_id + "&sub_appid=" +
                subappid + "&sub_mch_id=" + sub_mch_id
                + "&key=" + appKey;

        String sign2 = MD5Util.MD5Upper32(stringB);

        String res = "<xml>" +
                "<appid>" + appid + "</appid>" +
                "<mch_id>" + mch_id + "</mch_id>" +
                "<sub_mch_id>" + sub_mch_id + "</sub_mch_id>" +
                "<sub_appid>" + sub_appid + "</sub_appid>" +
                "<sign>" + sign2 + "</sign>" +
                "</xml>";


        System.out.println("res=" + res);


        HttpPost httpPost = new HttpPost(url);

        StringEntity stringEntity = new StringEntity(res, ContentType.APPLICATION_JSON);
        httpPost.setEntity(stringEntity);
        CloseableHttpResponse closeableResponse = HttpConnectionManager.getHttpClient().execute(httpPost);
        String wxresp = EntityUtils.toString(closeableResponse.getEntity(), "utf-8");

        System.out.println("resp=" + wxresp);


        Map<String, String> resultMap = parserXml(wxresp);

        if (resultMap.get("return_code").equals("SUCCESS")) {
            if (resultMap.get("result_code").equals("SUCCESS")) {
            }
        }
    }


    /**
     * 统一下单
     * @param openid
     * @param orderNo
     * @param total_fee
     * @param ip
     * @return
     */
    public String unifiedOrder(String openid, String orderNo, Long total_fee, String ip,
                               String sub_mch_id, String sub_appid, String attach){
        if (StringUtils.isEmpty(sub_mch_id)) {
            sub_mch_id = WXServerPayService.sub_mch_id;
        }

        if (StringUtils.isEmpty(sub_appid)) {
            sub_appid = WXServerPayService.sub_appid;
        }

        if (StringUtils.isEmpty(attach)) {
            attach = "商品支付";
        }

        Map<String, String> data = new HashMap<>();

        data.put("body", attach);
        data.put("out_trade_no", orderNo);
        data.put("total_fee", total_fee.toString());
        data.put("spbill_create_ip", ip);
        data.put("sub_appid", sub_appid);
        data.put("sub_mch_id", sub_mch_id);
        data.put("notify_url", serverPayNotifyUrl);
        data.put("trade_type", "JSAPI");
//        data.put("openid", openid);
        data.put("sub_openid", openid);

        try {
            System.out.println(data);
            Map<String, String> result = wxPay.unifiedOrder(data);

            LoggerUtil.console.info(result.toString());
            if (result != null) {
                String return_code = result.get("return_code");
                if (success.equals(return_code)) {
                    String result_code = result.get("result_code");
                    if (success.equals(result_code)) {
                        String prepay_id = result.get("prepay_id");
                        return prepay_id;
                    } else {
                        return null;
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static void main(String[] args)throws Exception {
//        new WXServerPayService().micropayCustomer("aasa22", "1", "117.136.8.102"
//        , "135181937822999766", "wx1e786d2271985b65", "1520468391"
//        );


//        new WXServerPayService().micropayCustomer("aasa22", "1", "117.136.8.102"
//        , "135181937822999766", WXServerPayService.sub_appid, "1520468391"
//        );

//        new WXServerPayService().unifiedOrder("oIs_H5X1QBGKy-dHLN9jTSy0rnQg","aaf22", 1l, "116.232.72.34"
//        , "1520468391", null
//        );

        new WXServerPayService().unifiedOrder("oyQ6P4mA40r_--iN86uQ-8kF7_mI","test13aa1a1", 1l, "125.113.105.63"
        , "1544092631", "wx4bf1260c290f196c", "aa"
//        , "1544092631", "wx099356561cb9c60f", "aa"
//        , "1544092631", sub_appid, "aa"
        );


//        new WXServerPayService().test("wx1e786d2271985b65");
    }

    /**
     * 提交付款码支付
     * @param orderNo 订单号
     * @param total_fee 总金额 单位为分
     * @param ip 终端ip
     * @param auth_code 用户支付二维码
     *
     * @return 支付结果：true成功  false失败
     */
    public boolean micropayCustomer(String orderNo, String total_fee, String ip, String auth_code, String sub_appid, String sub_mch_id){
        if (StringUtils.isEmpty(sub_mch_id)) {
            sub_appid = WXServerPayService.sub_appid;
            sub_mch_id = WXServerPayService.sub_mch_id;
        }

        Map<String, String> data = new HashMap<>();
        data.put("body", "商品支付");
        data.put("out_trade_no", orderNo);
        data.put("total_fee", total_fee);
        data.put("spbill_create_ip", ip);
        data.put("auth_code", auth_code);

        if (StringUtils.hasText(sub_appid)) {
            data.put("sub_appid", sub_appid);
        }

        data.put("sub_mch_id", sub_mch_id);
        try {

            LoggerUtil.console.info("microPay data : {}", JSONUtils.toJSONString(data));

            Map<String, String> result = wxPay.microPay(data);

            LoggerUtil.console.info(JsonUtil.toJson(result));
            if (result != null) {

                String return_code = result.get("return_code");

                LoggerUtil.console.info(return_code);

                if (success.equals(return_code)) {
                    String result_code = result.get("result_code");
                    LoggerUtil.console.info(result_code);
                    if (success.equals(result_code)) {
                        return true;
                    } else {
                        String err_code = result.get("err_code");
                        LoggerUtil.console.info(err_code);
                        if ("USERPAYING".equals(err_code)) {
                            //用户输入密码中，每隔5秒查询状态

                            int count = 0;
                            boolean doWhile = false;

                            Map<String, String> orderQueryData = new HashMap<>();
                            orderQueryData.put("out_trade_no", orderNo);
                            orderQueryData.put("sub_mch_id", sub_mch_id);

                            LoggerUtil.console.info(orderNo);

                            while(!doWhile) {
                                try {
                                    Thread.sleep(5 * 1000); //设置暂停的时间 5 秒
                                    count ++ ;
                                    LoggerUtil.console.info(sdf.format(new Date()) + "--订单查询支付状态请求第" + count + "次");


//                                    Map<String, String> orderQueryResult = wxPay.orderQuery(orderQueryData);
                                    Map<String, String> orderQueryResult = wxPay.orderQuery(orderQueryData);

                                    LoggerUtil.console.info(JsonUtil.toJson(orderQueryResult));
                                    String order_return_code = orderQueryResult.get("return_code");

                                    if (success.equals(order_return_code)) {
                                        String order_result_code = orderQueryResult.get("result_code");
                                        LoggerUtil.console.info("order_result_code : {}" , order_result_code);
                                        if (success.equals(order_result_code)) {
                                            LoggerUtil.console.info("order_result_code : {}" , order_result_code);
                                            String trade_state = orderQueryResult.get("trade_state");
                                            if (success.equals(trade_state)) {
                                                return true;
                                            } else if (!"USERPAYING".equals(trade_state)) {
                                                return false;
                                            }
                                        }
                                    }

                                    if (count == 6) {
                                        doWhile = true;

                                        //撤销订单
                                        wxPay.reverse(orderQueryData);
                                        return false ;
                                    }
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }

                        }
                    }

                } else {
                    return false;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }



    /**
     * 支付通知回调
     * @param requestBody
     * @return
     */
    public String notify(String requestBody) {
        LoggerUtil.console.info("notify");

        Map<String, String> resultMap = parserXml(requestBody);

        LoggerUtil.console.info("weixin server pay resultMap:  " + resultMap);

        String stringA = getPostSign(resultMap);

        String out_trade_no = resultMap.get("out_trade_no");

        if (StringUtils.isEmpty(out_trade_no)) {
            return responseFail;
        }

        String stringSignTemp = "";

        stringSignTemp = stringA + "key=" + WXServerPayService.appKey;


        String sign = MD5Util.MD5Upper32(stringSignTemp);

        if (!sign.equals(resultMap.get("sign")))
        {
            return responseFail;
        }

        String appid = resultMap.get("appid");
        String mch_id = resultMap.get("mch_id");
        String device_info = resultMap.get("device_info");
        String nonce_str = resultMap.get("nonce_str");
        String result_code = resultMap.get("result_code");
        String err_code = resultMap.get("err_code");
        String err_code_des = resultMap.get("err_code_des");
        String openid = resultMap.get("openid");
        String is_subscribe = resultMap.get("is_subscribe");
        String trade_type = resultMap.get("trade_type");
        String bank_type = resultMap.get("bank_type");
        String total_fee = resultMap.get("total_fee");
        String fee_type = resultMap.get("fee_type");
        String cash_fee = resultMap.get("cash_fee");
        String cash_fee_type = resultMap.get("cash_fee_type");
        String coupon_fee = resultMap.get("coupon_fee");
        String coupon_count = resultMap.get("coupon_count");
        String transaction_id = resultMap.get("transaction_id");

        String attach = resultMap.get("attach");
        String time_end = resultMap.get("time_end");

        if ("SUCCESS".equals(result_code)) {
            try {
                orderService.updateCardOrder(out_trade_no, transaction_id, time_end);
            } catch (Exception e) {
                e.printStackTrace();
                return responseFail;
            }
        } else {
            return responseFail;
        }

        System.out.println("return to wx=" + responseSuccess);

        return responseSuccess;
    }



    public static Map<String, String> parserXml(String content) {
        SAXReader saxReader = new SAXReader();
        Map<String, String> resultMap = new HashMap<>();
        try {
            StringReader stringReader = new StringReader(content);
            Document document = saxReader.read(stringReader);
            Element employees = document.getRootElement();


            for (Iterator i = employees.elementIterator(); i.hasNext();) {
                Element employee = (Element) i.next();
                System.out.println(employee.getName() + ":" + employee.getText());

                resultMap.put(employee.getName(), employee.getText());
            }
        } catch (DocumentException e) {
            System.out.println(e.getMessage());
        }
        System.out.println("dom4j parserXml");

        return resultMap;
    }

    private static String getPostSign(Map map)
    {
        // 对参数名进行字典排序
        Set strings = map.keySet();
        String[] keyArray = (String[])strings.toArray(new String[strings.size()]);

        Arrays.sort(keyArray, String.CASE_INSENSITIVE_ORDER);

        // 拼接有序的参数名-值串
        StringBuilder stringBuilder = new StringBuilder();
        for (String key : keyArray)
        {
            if ("sign".equals(key))
            {
                continue;
            }
            stringBuilder.append(key).append("=").append(map.get(key)).append("&");
        }
        return stringBuilder.toString();
    }
}
